home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / AOCE Sample Code / PowerTalk Access Modules / Sample SMSAM / SampleSMSAM Source / BuildingBlocks / HeapTools.cp < prev    next >
Encoding:
Text File  |  1995-07-28  |  24.5 KB  |  1,167 lines  |  [TEXT/KAHL]

  1. /*
  2.     File:        HeapTools.cp
  3.  
  4.     Copyright:    © 1991-1994 by Apple Computer, Inc.
  5.                 All rights reserved.
  6.  
  7.     Part of the AOCE Sample SMSAM Package.  Consult the license
  8.     which came with this software for your specific legal rights.
  9.  
  10. */
  11.  
  12.  
  13.  
  14. #pragma trace off
  15.  
  16. #ifndef    __HEAPTOOLS__
  17. #include "HeapTools.h"
  18. #endif
  19.  
  20. #ifndef    __CURSORCTL__
  21. // #include "CursorCtl.h"
  22. #endif
  23.  
  24. #ifndef    __RESOURCES__
  25. #include "Resources.h"
  26. #endif
  27.  
  28. #ifndef    __STANDARDFILE__
  29. #include "StandardFile.h"
  30. #endif
  31.  
  32. #ifndef    __ERRORS__
  33. #include "Errors.h"
  34. #endif
  35.  
  36. #ifndef    __STDARG__
  37. #include "StdArg.h"
  38. #endif
  39.  
  40. #ifndef    __NEWDELETE__
  41. #include "NewDelete.h"
  42. #endif
  43.  
  44. #ifndef    __STRING__
  45. #include "String.h"
  46. #endif
  47.  
  48. #ifndef    __STDIO__
  49. #include "StdIO.h"
  50. #endif
  51.  
  52. #ifndef    __DEBUGGINGGEAR__
  53. #include "DebuggingGear.h"
  54. #endif
  55.  
  56. #ifndef    __DIRECTOBJECT__
  57. #include "DirectObject.h"
  58. #endif
  59.  
  60. #ifndef    __HANDLEOBJECT__
  61. #include "HandleObject.h"
  62. #endif
  63.  
  64. extern ostream& DumpHex (ostream& s, const void *pv, unsigned long size);
  65. extern short gBovineWorkingVRefNum;
  66. extern long gBovineTempDirID;
  67.  
  68. #pragma segment HeapTools
  69.  
  70. const OSType kHeapArchiveCreator = 'MPS ';
  71. const OSType kHeapArchiveType = 'HEAP';
  72.  
  73. /***********************************|****************************************/
  74. /***********************************|****************************************/
  75.  
  76. struct LookupEntry
  77. {
  78.     const void*        fIdentifier;
  79.     Ptr                fInfo;
  80. };
  81.  
  82. static LookupEntry** gLookupVector = nil;
  83. static unsigned long gLookupCount = 0;
  84.  
  85. /***********************************|****************************************/
  86.  
  87. void Register ( const void* identifier, const char* file, unsigned long line )
  88. {
  89.     if ( gLookupVector )
  90.     {
  91.         ::HUnlock ( (Handle) gLookupVector );
  92.         ::SetHandleSize ( (Handle) gLookupVector, ( gLookupCount + 1 ) * sizeof ( LookupEntry ) );
  93.     }
  94.     else
  95.     {
  96.         gLookupVector = (LookupEntry**) ::NewHandleSys ( sizeof ( LookupEntry ) );
  97.     }
  98.     
  99.     if ( !MemError () ) 
  100.     {
  101.         ::MoveHHi ( (Handle) gLookupVector );
  102.         ::HLock ( (Handle) gLookupVector );
  103.         ( *gLookupVector ) [ gLookupCount ].fIdentifier = identifier;
  104.         
  105.         if ( file )
  106.         {
  107.             char buffer [ 64 ];
  108.             unsigned long length = ::sprintf ( buffer, "%s:%li", file, line ) + 1;
  109.             Ptr info = ::NewPtrSys ( length );
  110.             
  111.             if ( info )
  112.                 ::BlockMove ( buffer, info, length );
  113.             
  114.             ( *gLookupVector ) [ gLookupCount ].fInfo = info;
  115.         }
  116.         else
  117.         {
  118.             ( *gLookupVector ) [ gLookupCount ].fInfo = nil;
  119.         }
  120.         
  121.         gLookupCount++;
  122.     }
  123. }
  124.  
  125. /***********************************|****************************************/
  126.  
  127. void Unregister ( const void* identifier )
  128. {
  129.     register unsigned long index = gLookupCount;
  130.     
  131.     while ( index-- > 0 )
  132.     {
  133.         if ( ( *gLookupVector ) [ index ].fIdentifier == identifier ) 
  134.         {
  135.             if ( ( *gLookupVector ) [ index ].fInfo )
  136.                 ::DisposePtr ( ( *gLookupVector ) [ index ].fInfo );
  137.  
  138.             if ( index < --gLookupCount )
  139.                 ::BlockMove ( ( *gLookupVector ) + index + 1, ( *gLookupVector ) + index, ( gLookupCount - index ) * sizeof ( LookupEntry ) );
  140.             
  141.             ::HUnlock ( (Handle) gLookupVector );
  142.             ::SetHandleSize ( (Handle) gLookupVector, gLookupCount * sizeof ( LookupEntry ) );
  143.             ::MoveHHi ( (Handle) gLookupVector );
  144.             ::HLock ( (Handle) gLookupVector );
  145.  
  146.             break;
  147.         }
  148.     }
  149. }
  150.  
  151. /***********************************|****************************************/
  152.  
  153. LookupEntry* Find ( const void* identifier )
  154. {
  155.     register unsigned long index = gLookupCount;
  156.     
  157.     while ( index-- > 0 )
  158.         if ( ( *gLookupVector ) [ index ].fIdentifier == identifier ) 
  159.             return ( *gLookupVector ) + index;
  160.  
  161.     return nil;
  162. }
  163.  
  164. /***********************************|****************************************/
  165. /***********************************|****************************************/
  166.  
  167. inline OSErr Write ( short r, const void* p, unsigned long l )
  168. {
  169.     long b = l;
  170.     return ::FSWrite ( r, &b, p );
  171. }
  172.  
  173. /***********************************|****************************************/
  174.  
  175. inline OSErr Read ( short r, void* p, unsigned long l )
  176. {
  177.     long b = l;
  178.     return ::FSRead ( r, &b, p );
  179. }
  180.  
  181. /***********************************|****************************************/
  182. /***********************************|****************************************/
  183.  
  184. BlockInfo::BlockInfo ():
  185.     fZone ( nil ),
  186.     fStart ( nil ),
  187.     fMode32 ( GetMMUMode () ),
  188.     fMarked ( false )
  189. {
  190. }
  191.  
  192. /***********************************|****************************************/
  193.  
  194. BlockInfo::BlockInfo ( const Zone* zone ):
  195.     fZone ( zone ),
  196.     fStart ( nil ),
  197.     fMode32 ( GetMMUMode () ),
  198.     fMarked ( false )
  199. {
  200. }
  201.  
  202. /***********************************|****************************************/
  203.  
  204. BlockInfo::BlockInfo ( const BlockInfo& that ):
  205.     fZone ( that.fZone ),
  206.     fStart ( that.fStart ),
  207.     fHeader ( that.fHeader ),
  208.     fMode32 ( that.fMode32 ),
  209.     fMarked ( that.fMarked )
  210. {
  211. }
  212.  
  213. /***********************************|****************************************/
  214.  
  215. BlockInfo::~BlockInfo ()
  216. {
  217. }
  218.  
  219. /***********************************|****************************************/
  220.  
  221. BlockInfo&
  222. BlockInfo::operator = ( const BlockInfo& that )
  223. {
  224.     if ( this != &that )
  225.     {
  226.         fZone = that.fZone;
  227.         fStart = that.fStart;
  228.         fHeader = that.fHeader;
  229.         fMode32 = that.fMode32;
  230.         fMarked = false;
  231.     }
  232.  
  233.     return *this;
  234. }
  235.  
  236. /***********************************|****************************************/
  237.  
  238. Boolean
  239. BlockInfo::operator == ( register const BlockInfo& that ) const
  240. {
  241.     if ( fMode32 != that.fMode32 )
  242.         return false;
  243.     else if ( fHeader.f32.fType != that.fHeader.f32.fType )
  244.         return false;
  245.     else if ( GetIdentifierAddress () != that.GetIdentifierAddress () )
  246.         return false;
  247.     else if ( GetLogicalSize () != that.GetLogicalSize () )
  248.         return false;
  249.  
  250.     return true;
  251. }
  252.  
  253. /***********************************|****************************************/
  254.  
  255. const void*
  256. BlockInfo::GetIdentifierAddress () const
  257. {
  258.     if ( !fZone )
  259.     {
  260.         return fStart;
  261.     }
  262.     else if ( fHeader.f32.fType == kRelocatable )
  263.     {
  264.         if ( fMode32 )
  265.             return (Handle) ( (unsigned long) fHeader.f32.u.fRelativeHandle + (unsigned long) fZone );
  266.         else
  267.             return (Handle) ( (unsigned long) fHeader.f24.u.fRelativeHandle + (unsigned long) fZone );
  268.     }
  269.     else
  270.     {
  271.         return (const void*) ( (unsigned long) fStart + BlockHeaderSize () );
  272.     }
  273. }
  274.  
  275. /***********************************|****************************************/
  276.  
  277. const void* BlockInfo::GetLogicalStart () const
  278. {
  279.     if ( !fZone )
  280.     {
  281.         return nil;
  282.     }
  283.     else if ( fHeader.f32.fType == kRelocatable )
  284.     {
  285.         if ( fMode32 )
  286.             return *(Handle) ( (unsigned long) fHeader.f32.u.fRelativeHandle + (unsigned long) fZone );
  287.         else
  288.             return *(Handle) ( (unsigned long) fHeader.f24.u.fRelativeHandle + (unsigned long) fZone );
  289.     }
  290.     else
  291.     {
  292.         return (const void*) ( (unsigned long) fStart + BlockHeaderSize () );
  293.     }
  294. }
  295.  
  296. /***********************************|****************************************/
  297.  
  298. OSErr BlockInfo::Write ( short refNum ) const
  299. {
  300.     ::Write ( refNum, &((BlockInfo*)this)->fMode32, sizeof ( fMode32 ) );
  301.     const void* address = GetIdentifierAddress ();
  302.     ::Write ( refNum, &address, sizeof ( address ) );
  303.  
  304.     if ( fMode32 )
  305.         return ::Write ( refNum, &((BlockInfo*)this)->fHeader.f32, sizeof ( fHeader.f32 ) );
  306.     else
  307.         return ::Write ( refNum, &((BlockInfo*)this)->fHeader.f24, sizeof ( fHeader.f24 ) );
  308. }
  309.  
  310. /***********************************|****************************************/
  311.  
  312. OSErr BlockInfo::Read ( short refNum )
  313. {
  314.     fZone = nil;
  315.     ::Read ( refNum, &fMode32, sizeof ( fMode32 ) );
  316.     ::Read ( refNum, &fStart, sizeof ( fStart ) );
  317.  
  318.     if ( fMode32 )
  319.         return ::Read ( refNum, &fHeader.f32, sizeof ( fHeader.f32 ) );
  320.     else
  321.         return ::Read ( refNum, &fHeader.f24, sizeof ( fHeader.f24 ) );
  322. }
  323.  
  324. /***********************************|****************************************/
  325.  
  326. void
  327. BlockInfo::Set ( const void* blockHeader )
  328. {
  329.     fStart = blockHeader;
  330.  
  331.     if ( fMode32 )
  332.         fHeader.f32 = *(const BlockHeader32*) blockHeader;
  333.     else
  334.         fHeader.f24 = *(const BlockHeader24*) blockHeader;
  335. }
  336.  
  337. /***********************************|****************************************/
  338.  
  339. ostream&
  340. BlockInfo::operator >> ( ostream& s ) const
  341. {
  342.     if ( fMode32 )
  343.         return Stream32 ( s );
  344.     else
  345.         return Stream24 ( s );
  346. }
  347.  
  348. /***********************************|****************************************/
  349.  
  350. ostream&
  351. StreamType ( ostream& s, BlockInfo::BlockType type )
  352. {
  353.     switch ( type )
  354.     {
  355.         case BlockInfo::kNonrelocatable:
  356.             s << "ptr";
  357.         break;
  358.  
  359.         case BlockInfo::kRelocatable:
  360.             s << "handle";
  361.         break;
  362.  
  363.         case BlockInfo::kFree:
  364.             s << "free";
  365.         break;
  366.     }
  367.  
  368.     return s;
  369. }
  370.  
  371. /***********************************|****************************************/
  372.  
  373. ostream&
  374. BlockInfo::Stream24 ( ostream& s ) const
  375. {
  376.     s << (void*) GetIdentifierAddress () << ", ";
  377.     StreamType ( s, (BlockType) fHeader.f24.fType );
  378.     return s << ", " << GetLogicalSize ();
  379. }
  380.  
  381. /***********************************|****************************************/
  382.  
  383. inline unsigned long min ( unsigned long a, unsigned long b )
  384. {
  385.     return ( a < b ) ? a : b ;
  386. }
  387.  
  388. /***********************************|****************************************/
  389.  
  390. static void ShowBlockData ( ostream& s, const void* start, unsigned long size )
  391. {
  392.     size = min ( size, 8 );
  393.  
  394.     s << "|";
  395.     for ( unsigned short i = 0; i < size; ++ i )
  396.     {    unsigned char c = ((unsigned char *) start)[i];
  397.         c = ( c < 32 ) ? ' ' : c;
  398.         s << c;
  399.     };
  400.  
  401.     s << " | $";
  402.     for ( i = 0; i < size; ++ i )
  403.         s << hex << (unsigned short) ((unsigned char*) start)[i] << dec << " ";
  404. }
  405.  
  406. /***********************************|****************************************/
  407. ostream&
  408. BlockInfo::Stream32 ( ostream& s ) const
  409. {
  410.     const void* start = GetLogicalStart ();
  411.     const void* identifier = GetIdentifierAddress ();
  412.     unsigned long size = GetLogicalSize ();
  413.  
  414.     extern void * g2020HalfGateway;
  415.     if ( g2020HalfGateway == identifier )
  416.         Debugger();
  417.  
  418.     s << (void*) identifier << ", ";
  419.     StreamType ( s, (BlockType) fHeader.f32.fType );
  420.     s << ", "; s.width ( 5 ); s << size;
  421.  
  422.     if ( fHeader.f32.fType == kRelocatable )
  423.     {
  424.         if ( fHeader.f32.fLocked )
  425.             s << ", locked";
  426.  
  427.         if ( fHeader.f32.fPurgeable )
  428.             s << ", purgeable";
  429.  
  430.         if ( fHeader.f32.fResource && fZone )
  431.         {
  432.             Str255 name;
  433.             short id = 0;
  434.             char type [ 5 ];
  435.             type [ 4 ] = 0;
  436.  
  437.             ::GetResInfo ( (Handle) identifier, &id, (OSType*) &type, name );
  438.  
  439.             if ( !ResError () )
  440.             {
  441.                 s << ", " << (char*) &type << " " << id;
  442.     
  443.                 if ( name [ 0 ] > 0 )
  444.                 {
  445.                     name [ name [ 0 ] + 1 ] = 0;
  446.                     s << " \"" << (char*) name + 1 << "\"";
  447.                 }
  448.             }
  449.         }
  450.     }
  451.     s << flush;
  452.     
  453. #if defined ( debug )
  454.  
  455.     if ( fZone && start )
  456.     {    
  457.         #if THINK_CPLUS
  458.         //    Think C++ doesn't use HandleObjects, so they're really just DirectObjects.
  459.         //    Additionally, it always stuffs '$FFFF' into the first word of
  460.         //    every allocated block ( for some reason ) and so the real object
  461.         //    data starts 'after' the first word.
  462.         const void * actualDataStart = ( (char*) identifier ) + 2;
  463.         if ( ( fHeader.f32.fType != kRelocatable ) &&
  464.              ( THandleObject::IsAHandleObject ( (Handle) actualDataStart ) ) )
  465.         {
  466.             s << ", " << * ( THandleObject * ) actualDataStart;
  467.         }
  468.         else if ( ( fHeader.f32.fType != kRelocatable ) &&
  469.                     ( TDirectObject::IsADirectObject ( (Ptr) actualDataStart ) ) )
  470.         {
  471.             s << ", " << * ( TDirectObject * ) actualDataStart;
  472.         }
  473.         #else
  474.         if ( ( fHeader.f32.fType == kRelocatable ) &&
  475.              ( THandleObject::IsAHandleObject ( (Handle) identifier ) ) )
  476.         {
  477.             s << ", " << * ( THandleObject * ) identifier;
  478.         }
  479.         else if ( ( fHeader.f32.fType != kRelocatable ) &&
  480.                     ( TDirectObject::IsADirectObject ( (Ptr) start ) ) )
  481.         {
  482.             s << ", " << * ( TDirectObject * ) start;
  483.         }
  484.         #endif
  485.         else
  486.         {
  487.             const LookupEntry* entry = Find ( identifier );
  488.                         
  489.             if ( entry && entry->fInfo )
  490.                 s << ", " << (char*) entry->fInfo;
  491.             else if ( fHeader.f32.fType == kRelocatable )
  492.             {
  493.                 if ( !fHeader.f32.fResource)
  494.                     ShowBlockData ( s, start, size );
  495.             }
  496.             else if ( fHeader.f32.fType != kRelocatable )
  497.                 ShowBlockData ( s, start, size );
  498.         }
  499.     }
  500.     
  501. #endif
  502.  
  503.     return s;
  504. }
  505.  
  506. /***********************************|****************************************/
  507. /***********************************|****************************************/
  508.  
  509. THeapWalker::THeapWalker ( const Zone* zone ):
  510.     fZone ( zone ),
  511.     fStart ( &((Zone*)fZone)->heapData ),
  512.     fEnd ( fZone->bkLim ),
  513.     fCurrent ( nil ),
  514.     fBlock ( fZone )
  515. {
  516. }
  517.  
  518. /***********************************|****************************************/
  519.  
  520. THeapWalker::~THeapWalker ()
  521. {
  522. }
  523.  
  524. /***********************************|****************************************/
  525.  
  526. void THeapWalker::Reset ()
  527. {
  528.     fCurrent = nil;
  529. }
  530.  
  531. /***********************************|****************************************/
  532.  
  533. Boolean THeapWalker::Next ()
  534. {
  535.     if ( !fZone )
  536.     {
  537.         return false;    // we were loaded in from disk, so we cannot walk the heap
  538.     }
  539.     if ( fCurrent == nil )
  540.     {
  541.         fCurrent = fStart;
  542.         fBlock.Set ( fCurrent );
  543.         return true;
  544.     }
  545.     else if ( fCurrent < fEnd )
  546.     {
  547.         fCurrent = fBlock.NextBlockHeader ();
  548.         fBlock.Set ( fCurrent );
  549.         return fCurrent < fEnd;
  550.     }
  551.     else
  552.     {
  553.         return false;
  554.     }
  555. }
  556.  
  557. /***********************************|****************************************/
  558.  
  559. const BlockInfo& THeapWalker::GetCurrent ()
  560. {
  561.     return fBlock;
  562. }
  563.  
  564. /***********************************|****************************************/
  565. /***********************************|****************************************/
  566.  
  567. THeapState::THeapState ():
  568.     fCount ( 0 ),
  569.     fBlocks ( nil )
  570. {
  571. }
  572.  
  573. /***********************************|****************************************/
  574.  
  575. THeapState::THeapState ( const Zone* zone ):
  576.     fCount ( 0 ),
  577.     fBlocks ( nil )
  578. {
  579.     Copy ( zone );
  580. }
  581.  
  582. /***********************************|****************************************/
  583.  
  584. THeapState::THeapState ( const FSSpec& spec ):
  585.     fCount ( 0 ),
  586.     fBlocks ( nil )
  587. {
  588.     Load ( spec );
  589. }
  590.  
  591. /***********************************|****************************************/
  592.  
  593. THeapState::THeapState ( const THeapState& that ):
  594.     fCount ( 0 ),
  595.     fBlocks ( nil )
  596. {
  597.     Copy ( that );
  598. }
  599.  
  600. /***********************************|****************************************/
  601.  
  602. THeapState::~THeapState ()
  603. {
  604.     delete fBlocks;
  605. }
  606.  
  607. /***********************************|****************************************/
  608.  
  609. THeapState&
  610. THeapState::operator = ( const THeapState& heap )
  611. {
  612.     if ( this != &heap )
  613.         Copy ( heap );
  614.     
  615.     return *this;
  616. }
  617.  
  618. /***********************************|****************************************/
  619.  
  620. Boolean
  621. THeapState::operator == ( const THeapState& heap ) const
  622. {    
  623.     if ( fCount != heap.fCount )
  624.         return false;
  625.     
  626.     for ( unsigned long index = 0; index < fCount; index++ )
  627.         if ( fBlocks [ index ] != heap.fBlocks [ index ] )
  628.             return false;
  629.         
  630.     return true;
  631. }
  632.  
  633. /***********************************|****************************************/
  634.  
  635. Boolean
  636. THeapState::operator != ( const THeapState& heap ) const
  637. {    
  638.     if ( fCount != heap.fCount )
  639.         return true;
  640.     
  641.     for ( unsigned long index = 0; index < fCount; index++ )
  642.         if ( fBlocks [ index ] != heap.fBlocks [ index ] )
  643.             return true;
  644.  
  645.     return false;
  646. }
  647.  
  648. /***********************************|****************************************/
  649.  
  650. OSErr
  651. THeapState::Copy ( const Zone* zone )
  652. {
  653.     fCount = 0;
  654.     THeapWalker walker ( zone );
  655.  
  656.     while ( walker.Next () )
  657.         if ( walker.GetCurrent ().GetType () != BlockInfo::kFree )
  658.             ++fCount;
  659.  
  660.     delete fBlocks;
  661.     
  662.     SetZone ( SystemZone () );
  663.     fBlocks = new BlockInfo [ fCount ];
  664.     SetZone ( ApplicZone () );
  665.  
  666.     if ( fBlocks )
  667.     {
  668.         unsigned long index = 0;
  669.  
  670.         walker.Reset ();
  671.  
  672.         while ( walker.Next () && index < fCount )
  673.         {
  674.             const BlockInfo& block = walker.GetCurrent ();
  675.             
  676.             if ( block.GetIdentifierAddress () != fBlocks && block.GetType () != BlockInfo::kFree )
  677.                 fBlocks [ index++ ] = block;
  678.         }
  679.  
  680.         return noErr;
  681.     }
  682.     else
  683.     {
  684.         fCount = 0;
  685.         return memFullErr;
  686.     }
  687. }
  688.  
  689. /***********************************|****************************************/
  690.  
  691. OSErr
  692. THeapState::Copy ( const THeapState& heap )
  693. {
  694.     delete fBlocks;
  695.     SetZone ( SystemZone () );
  696.     fBlocks = new BlockInfo [ heap.fCount ];
  697.     SetZone ( ApplicZone () );
  698.  
  699.     if ( fBlocks )
  700.     {
  701.         fCount = heap.fCount;
  702.  
  703.         for ( unsigned long index = 0; index < fCount; index++ )
  704.             fBlocks [ index ] = heap.fBlocks [ index ];
  705.  
  706.         return noErr;
  707.     }
  708.     else
  709.     {
  710.         fCount = 0;
  711.         return memFullErr;
  712.     }
  713. }
  714.  
  715. /***********************************|****************************************/
  716.  
  717. const BlockInfo&
  718. THeapState::operator [] ( unsigned long index ) const
  719. {
  720.     if ( index < fCount && fBlocks )
  721.     {
  722.         return fBlocks [ index ];
  723.     }
  724.     else
  725.     {
  726.         static BlockInfo gBozoInfo;
  727.         return gBozoInfo;
  728.     }
  729. }
  730.  
  731. /***********************************|****************************************/
  732.  
  733. OSErr
  734. THeapState::Dump ()
  735. {
  736.     return Dump ( "\pSave archive as…" );
  737. }
  738.  
  739. /***********************************|****************************************/
  740.  
  741. OSErr
  742. THeapState::Dump ( const StringPtr prompt )
  743. {
  744.     StandardFileReply reply;
  745. #if defined ( BovineServer )
  746.     reply.sfFile.vRefNum = gBovineWorkingVRefNum;
  747.     reply.sfFile.parID = gBovineTempDirID;
  748. #endif
  749.     static unsigned long gCounter;
  750.     Str63 name;
  751.     PLstrcpy ( name, "\pHeap Archive X" );
  752.     name [ name [ 0 ] ] = '0' + (unsigned char) ++gCounter;
  753.     ::StandardPutFile ( prompt, name, &reply );
  754.     return reply.sfGood ? Dump ( reply.sfFile ) : -1;
  755. }
  756.  
  757. /***********************************|****************************************/
  758.  
  759. OSErr
  760. THeapState::Load ()
  761. {
  762.     StandardFileReply reply;
  763.  
  764. #if defined ( BovineServer )
  765.     reply.sfFile.vRefNum = gBovineWorkingVRefNum;
  766.     reply.sfFile.parID = gBovineTempDirID;
  767. #endif
  768.  
  769.     OSType type[4] = { kHeapArchiveType, '    ', '    ', '    '};
  770.     ::StandardGetFile ( nil, 1, type, &reply );
  771.     return reply.sfGood ? Load ( reply.sfFile ) : -1;
  772. }
  773.  
  774. /***********************************|****************************************/
  775.  
  776. OSErr
  777. THeapState::Dump ( const FSSpec& spec )
  778. {
  779.     OSErr error = ::FSpCreate ( &spec, kHeapArchiveCreator, kHeapArchiveType, 0 );
  780.  
  781.     if ( error && error != dupFNErr )
  782.         return error;
  783.  
  784.     short refNum = 0;
  785.     error = ::FSpOpenDF ( &spec, fsWrPerm, &refNum );
  786.  
  787.     if ( error )
  788.         return error;
  789.  
  790.     ::SetEOF ( refNum, 0 );
  791.     ::SetFPos ( refNum, fsFromStart, 0 );
  792.     unsigned long zero = 0;
  793.     ::Write ( refNum, &zero, sizeof ( zero ) );
  794.  
  795.     for ( unsigned long index = 0; index < fCount && !error; index++ )
  796.         error = fBlocks [ index ].Write ( refNum );
  797.  
  798.     ::SetFPos ( refNum, fsFromStart, 0 );
  799.     ::Write ( refNum, &fCount, sizeof ( fCount ) );
  800.     ::FSClose ( refNum );
  801.  
  802.     return error;
  803. }
  804.  
  805. /***********************************|****************************************/
  806.  
  807. OSErr
  808. THeapState::Load ( const FSSpec& spec )
  809. {
  810.     short refNum = 0;
  811.     OSErr error = ::FSpOpenDF ( &spec, fsRdPerm, &refNum );
  812.  
  813.     if ( error )
  814.         return error;
  815.  
  816.     delete fBlocks;
  817.     fBlocks = nil;
  818.     
  819.     ::SetFPos ( refNum, fsFromStart, 0 );
  820.     ::Read ( refNum, &fCount, sizeof ( fCount ) );
  821.  
  822.     if ( fCount > 0 )
  823.     {
  824.         SetZone ( SystemZone () );
  825.         fBlocks = new BlockInfo [ fCount ];
  826.         SetZone ( ApplicZone () );
  827.  
  828.         if ( fBlocks )
  829.         {
  830.             for ( unsigned long index = 0; index < fCount && !error; index++ )
  831.                 error = fBlocks [ index ].Read ( refNum );
  832.         }
  833.         else
  834.         {
  835.             error = MemError ();
  836. #if debug
  837.             chris << "failed to create array of " << fCount << " BlockInfos!" << flush;
  838. #endif
  839.             fCount = 0;
  840.         }
  841.     }
  842.  
  843.     ::FSClose ( refNum );
  844.  
  845.     return error;
  846. }
  847.  
  848. /***********************************|****************************************/
  849.  
  850. Boolean
  851. THeapState::Contains ( const BlockInfo& block ) const
  852. {
  853.     for ( unsigned long index = 0; index < fCount; index++ )
  854.         if ( fBlocks [ index ] == block )
  855.             return true;
  856.     
  857.     return false;
  858. }
  859.  
  860. /***********************************|****************************************/
  861.  
  862. void
  863. THeapState::UnmarkAllBlocks ()
  864. {
  865.     MarkAllBlocks ( false );
  866. }
  867.  
  868. /***********************************|****************************************/
  869.  
  870. void
  871. THeapState::MarkAllBlocks ( Boolean mark )
  872. {
  873.     for ( unsigned long index = 0; index < fCount; index++ )
  874.         fBlocks [ index ].SetMarked ( mark );
  875. }
  876.  
  877. /***********************************|****************************************/
  878.  
  879. unsigned long
  880. THeapState::MarkedBlocksCount () const
  881. {
  882.     unsigned long marked = 0;
  883.  
  884.     for ( unsigned long index = 0; index < fCount; index++ )
  885.         if ( fBlocks [ index ].IsMarked () )
  886.             marked++;
  887.     
  888.     return marked;
  889. }
  890.  
  891. /***********************************|****************************************/
  892.  
  893. unsigned long
  894. THeapState::MarkedBlocksSize () const
  895. {
  896.     unsigned long size = 0;
  897.  
  898.     for ( unsigned long index = 0; index < fCount; index++ )
  899.     {
  900.         const BlockInfo& block = fBlocks [ index ];
  901.         
  902.         if ( block.IsMarked () )
  903.             size += block.GetLogicalSize ();
  904.     }
  905.     
  906.     return size;
  907. }
  908.  
  909. /***********************************|****************************************/
  910.  
  911. unsigned long
  912. THeapState::HeapSize () const
  913. {
  914.     unsigned long size = 0;
  915.  
  916.     for ( unsigned long index = 0; index < fCount; index++ )
  917.         size += fBlocks [ index ].GetLogicalSize ();
  918.     
  919.     return size;
  920. }
  921.  
  922. /***********************************|****************************************/
  923.  
  924. THeapState&
  925. THeapState::operator -= ( THeapState& that )
  926. {
  927.     unsigned long index;
  928.  
  929.     for ( index = 0; index < fCount; index++ )
  930.     {
  931.         BlockInfo& block = fBlocks [ index ];
  932.         block.SetMarked ( !that.Contains ( block ) );
  933.     }
  934.  
  935.     unsigned long marked = MarkedBlocksCount ();
  936.     
  937.     if ( marked > 0 )
  938.     {
  939.         SetZone ( SystemZone () );
  940.         BlockInfo* blocks = new BlockInfo [ marked ];
  941.         SetZone ( ApplicZone () );
  942.         
  943.         if ( blocks )
  944.         {
  945.             unsigned long jndex = 0;
  946.             
  947.             for ( index = 0; index < fCount; index++ )
  948.             {
  949.                 const BlockInfo& block = fBlocks [ index ];
  950.                 
  951.                 if ( block.IsMarked () )
  952.                     blocks [ jndex++ ] = block;
  953.             }
  954.  
  955.             delete fBlocks;
  956.             fBlocks = blocks;
  957.             fCount = marked;
  958.         }
  959.         else
  960.         {
  961. #if debug
  962.             chris << "failed to allocate array of " << marked << " blocks!" << endl;
  963. #endif
  964.             delete fBlocks;
  965.             fBlocks = nil;
  966.             fCount = 0;
  967.         }
  968.     }
  969.     else
  970.     {
  971.         delete fBlocks;
  972.         fBlocks = nil;
  973.         fCount = 0;
  974.     }
  975.     
  976.     return *this;
  977. }
  978.  
  979. /***********************************|****************************************/
  980.  
  981. THeapState&
  982. THeapState::operator &= ( THeapState& that )
  983. {
  984.     unsigned long index;
  985.  
  986.     for ( index = 0; index < fCount; index++ )
  987.     {
  988.         BlockInfo& block = fBlocks [ index ];
  989.         block.SetMarked ( that.Contains ( block ) );
  990.     }
  991.  
  992.     unsigned long marked = MarkedBlocksCount ();
  993.     
  994.     if ( marked > 0 )
  995.     {
  996.         SetZone ( SystemZone () );
  997.         BlockInfo* blocks = new BlockInfo [ marked ];
  998.         SetZone ( ApplicZone () );
  999.         
  1000.         if ( blocks )
  1001.         {
  1002.             unsigned long jndex = 0;
  1003.             
  1004.             for ( index = 0; index < fCount; index++ )
  1005.             {
  1006.                 BlockInfo& block = fBlocks [ index ];
  1007.                 
  1008.                 if ( block.IsMarked () )
  1009.                     blocks [ jndex++ ] = block;
  1010.             }
  1011.  
  1012.             delete fBlocks;
  1013.             fBlocks = blocks;
  1014.             fCount = marked;
  1015.         }
  1016.         else
  1017.         {
  1018. #if debug
  1019.             chris << "failed to allocate array of " << marked << " blocks!" << endl;
  1020. #endif
  1021.             delete fBlocks;
  1022.             fBlocks = nil;
  1023.             fCount = 0;
  1024.         }
  1025.     }
  1026.     else
  1027.     {
  1028.         delete fBlocks;
  1029.         fBlocks = nil;
  1030.         fCount = 0;
  1031.     }
  1032.     
  1033.     return *this;
  1034. }
  1035.  
  1036. /***********************************|****************************************/
  1037.  
  1038. THeapState&
  1039. THeapState::operator ^= ( THeapState& that )
  1040. {
  1041.     unsigned long index;
  1042.  
  1043.     for ( index = 0; index < fCount; index++ )
  1044.     {
  1045.         BlockInfo& block = fBlocks [ index ];
  1046.         block.SetMarked ( !that.Contains ( block ) );
  1047.     }
  1048.  
  1049.     for ( index = 0; index < that.fCount; index++ )
  1050.     {
  1051.         BlockInfo& block = that.fBlocks [ index ];
  1052.         block.SetMarked ( !Contains ( block ) );
  1053.     }
  1054.  
  1055.     unsigned long marked = MarkedBlocksCount () + that.MarkedBlocksCount ();
  1056.  
  1057.     if ( marked > 0 )
  1058.     {
  1059.         SetZone ( SystemZone () );
  1060.         BlockInfo* blocks = new BlockInfo [ marked ];
  1061.         SetZone ( ApplicZone () );
  1062.         
  1063.         if ( blocks )
  1064.         {
  1065.             unsigned long jndex = 0;
  1066.             
  1067.             for ( index = 0; index < fCount; index++ )
  1068.             {
  1069.                 BlockInfo& block = fBlocks [ index ];
  1070.                 
  1071.                 if ( block.IsMarked () )
  1072.                     blocks [ jndex++ ] = block;
  1073.             }
  1074.  
  1075.             for ( index = 0; index < that.fCount; index++ )
  1076.             {
  1077.                 BlockInfo& block = that.fBlocks [ index ];
  1078.                 
  1079.                 if ( block.IsMarked () )
  1080.                     blocks [ jndex++ ] = block;
  1081.             }
  1082.  
  1083.             delete fBlocks;
  1084.             fBlocks = blocks;
  1085.             fCount = marked;
  1086.         }
  1087.         else
  1088.         {
  1089. #if debug
  1090.             chris << "failed to allocate array of " << marked << " blocks!" << endl;
  1091. #endif
  1092.             delete fBlocks;
  1093.             fBlocks = nil;
  1094.             fCount = 0;
  1095.         }
  1096.     }
  1097.     else
  1098.     {
  1099.         delete fBlocks;
  1100.         fBlocks = nil;
  1101.         fCount = 0;
  1102.     }
  1103.     
  1104.     return *this;
  1105. }
  1106.  
  1107. /***********************************|****************************************/
  1108.  
  1109. ostream&
  1110. THeapState::operator >> ( ostream& s ) const
  1111. {
  1112.     s << fCount << " blocks, " << HeapSize () << " bytes" << endl;
  1113.  
  1114.     for ( unsigned long index = 0; index < fCount; index++ )
  1115.         s << index + 1 << ": " << fBlocks [ index ] << endl;
  1116.  
  1117.     return s;
  1118. }
  1119.  
  1120. /***********************************|****************************************/
  1121.  
  1122. void ViewCurrentHeap ()
  1123. {
  1124. #if debug
  1125.     THeapState heap ( ApplicationZone () );
  1126.     chris << heap << endl;
  1127. #endif
  1128. }
  1129.  
  1130. /***********************************|****************************************/
  1131.  
  1132. void ViewArchivedHeap ()
  1133. {
  1134. #if debug
  1135.     THeapState heap;
  1136.     heap.Load ();
  1137.     chris << heap << endl;
  1138. #endif
  1139. }
  1140.  
  1141. /***********************************|****************************************/
  1142.  
  1143. void ArchiveCurrentHeap ()
  1144. {
  1145. #if debug
  1146.     THeapState heap ( ApplicationZone () );
  1147.     heap.Dump ();
  1148. #endif
  1149. }
  1150.  
  1151. /***********************************|****************************************/
  1152.  
  1153. void CompareCurrentHeapWithArchive ()
  1154. {
  1155. #if debug
  1156.     THeapState state1 ( ApplicationZone () ), state2;
  1157.  
  1158.     if ( state2.Load () == noErr )
  1159.     {
  1160.         state1 -= state2;
  1161.         chris << state1 << endl;
  1162.     }
  1163. #endif
  1164. }
  1165.  
  1166. /***********************************|****************************************/
  1167.